<?php
class User extends Zend_Db_Table_Abstract {
	
	protected $_primary = 'id';
	protected $_name = 'user';
	
	const INTRODUCTION = 'introduction';
	const BIG_IMG = 'big_img';
	const SQUARE_IMG = 'square_img';
	const NAME = "name";
	const LOCATION = "location";
	
	protected $_dependentTables = array(
	   'UserBook',
	   'UserMessage',
	   'Message',
	   'Activity',
	   'ResetPasswordRequest',
	   'UserCredentials'
    );
    
    protected $_referenceMap = array (
    'City' => array (
        'columns' => 'location', 
        'refTableClass' => 'City', 
        'refColumns' => 'id' 
    )
    );
	
    public function findById($id) {
    	return $this->find($id)->current();
    }
    
	/**
	 * Add user data.
	 * 
	 * @param $data
	 * @return return added user
	 */
	public function addUser($data) {
		$user = $this->findByEmailAndPassword($data["email"], $data["password"]);
		if (!isset($user)) {
			$user = $this->insert($data);
		}
		return $user;
	}
	
	/**
	 * Add new facebook user.
	 * 
	 * @param $data
	 * @return return user
	 */
	public function addFacebookUser($data) {
		$user = $this->findFacebookUserByEmail($data["email"]);
		if (!isset($user)) {
			$userId = $this->insert($data);
			$user = $this->findById($userId);
		} else {
			$user->last_access = $data["last_access"];
			$user->save();
		}
		return $user;
	}
	
	/**
	 * Find user by email. It should be ONE and ONLY ONE user with given email.
	 * 
	 * @param $email
	 */
	public function findByEmail($email) {
		$select = $this->select()->where("email = ?", $email);
		return $this->fetchRow($select);
	}
	
	/**
	 * Find facebook user by email.
	 * 
	 * @param $email
	 * @return return user object if any
	 */
	public function findFacebookUserByEmail($email) {
		$select = $this->select()
        ->setIntegrityCheck(false)
        ->from(array("u"=>"user"), array("email"))
        ->join(array("uc"=>"user_credentials"), "u.id=uc.user_id", array("id"=>"user_id"))
        ->where("uc.auth_provider=?", AuthProvider::FACEBOOK)
        ->where("upper(u.email)=upper(?)", $email)
        ->where("uc.status=?", UserCredentialStatus::ACTIVE);
        
        $data = $this->fetchRow($select);
        return $this->findById($data["id"]);
	}
	
	/**
	 * Find user by email and password.
	 * 
	 * @param $email
	 * @param $password
	 * @return return found user
	 */
	public function findByEmailAndPassword($email, $password) {
		$select = $this->select()->where("upper(email)=upper(?)", $email)
		->where("password=?", $password)
		->where("status='".UserStatus::PENDING."' OR status='".UserStatus::ACTIVE."'");
		return $this->fetchRow($select);
	}
	
	
	/**
	 * Find pending user by given key and email.
	 * 
	 * @param $key
	 * @param $email
	 * @return return found user
	 */
	public function findUserByKeyAndEmail($key, $email) {
		$where = $this->select()->where("registration_key=?", $key)
		->where("email=?", $email);
		return $this->fetchRow($where);
	}
	
	/**
	 * Update user status.
	 * 
	 * @param $id user id
	 * @param $status status to be updated
	 * @param $activated activated time
	 */
	public function updateUserStatus($id, $status, $activated) {
		$user = $this->find($id)->current();
		$user->status = $status;
		$user->activated = $activated;
		$user->save();
	}
	
	/**
	 * Update user last access date.
	 * 
	 * @param $id
	 * @param $lastAccess
	 */
	public function updateLastAccess($id, $lastAccess) {
		$user = $this->findById($id);
        $user->last_access = $lastAccess;
        $user->save();
	}
	
	/**
	 * Update user settings.
	 * 
	 * @param $user_id
	 * @param $data
	 */
	public function updateUserSettings($user_id, $data) {
		$user = $this->findById($user_id);
		if (isset($user)) {
			if (isset($data[self::BIG_IMG]) && $data[self::BIG_IMG] != "") {
			    $user->big_img = $data[self::BIG_IMG];
			}
		    if (isset($data[self::SQUARE_IMG]) && $data[self::SQUARE_IMG] != "") {
                $user->square_img = $data[self::SQUARE_IMG];
            }
			if (isset($data[self::INTRODUCTION]) && $data[self::INTRODUCTION] != "")
				$user->introduction = $data[self::INTRODUCTION];
			if (isset($data[self::NAME]) && $data[self::NAME] != "")
				$user->name = $data[self::NAME];
			if (isset($data[self::LOCATION]) && $data[self::LOCATION] != "")
				$user->location = $data[self::LOCATION];
			$user->save();
		}
	}
	
	/**
	 * Return books which the given user have.
	 * 
	 * @param $user
	 * @param $status
	 */
	public static function getBooks($user, $status) {
		$userBook = new UserBook();
		return $user->findManyToManyRowset('Book', 'UserBook', 'User', 'Book', $userBook->select()->where('i.status=?', $status)->order('i.created DESC'));
	}
		
	/**
	 * Reture messages which sent to given user.
	 * 
	 * @param $user
	 */
	public static function getUserMessage($user) {
		$userMessage = new UserMessage();
		return $user->findManyToManyRowset('Message', 'UserMessage', 'TargetUser', 'Message', $userMessage->select()->where('i.status!=?', 'deleted')->order('created DESC'));
	}
	
	/**
	 * Return messages which sent by given user.
	 * 
	 * @param $user
	 */
	public static function getMessageSentByUser($user) {
		$ret = array();
		$message = new Message();
		$index = 0;
		foreach ($user->findDependentRowset('Message', 'User', $message->select()->order('created DESC')) as $message) {
			$userMessage = Message::getUserMessage($message);
			if (isset($userMessage)) {
				$ret[$index++] = $message;
			}
		}
		return $ret;
	}
	
	/**
	 * Get unread message sent to given user.
	 * 
	 * @param $user
	 * @return return user messages
	 */
	public static function getUnreadMessageByUser($user) {
		$table = new UserMessage();
		$userMessages = $user->findDependentRowset('UserMessage', 'TargetUser', $table->select()->where("status=?", UserMessageStatus::UNREAD));
		return $userMessages;
	} 
	
	/**
	 * Return city where the user belong to.
	 * 
	 * @param $user
	 */
	public static function getCity($user) {
		return $user->findParentRow("City");
	}
	
	/**
	 * Get user top city, top city is the city which has no parent city.
	 * 
	 * @param $user
	 */
	public static function getTopCity($user) {
		$city = User::getCity($user);
		return City::getTopCity($city->id);
	}
	
    /**
     * Return user name string is exist.
     */
    public static function getUserName($user) {
        $nameStr = "";
        if (!empty($user)) {
            if(empty($user->name)) {
                $nameStr.="Unknown Name";
            } else {
                $nameStr.=$user->name;
            }
            $nameStr.="(".$user->email.")";
        }
        return $nameStr;
    }
    
    /**
     * Return user group.
     */
    public static function getUserGroup($user) {
        return User::getCity($user)->name;
    }
    
    /**
     * Return actvities did by given user.
     * 
     * @param $user
     * @param $limit
     */
    public static function getActivityByUser($user, $limit=10) {
    	$activity = new Activity();
    	return $user->findDependentRowset("Activity", "User", $activity->select()->where("activity.type in (?)", array(Activity::ACTIVATE_USER, Activity::USER_ADD_BOOK))->order("created DESC")->limit($limit));
    }
    
    /**
     * Return all activities related by given city.
     * 
     * @param $cityId cityid, like stockholm, it must be the top city
     * @param $limit
     */
    public static function getActivityByUserCity($cityId, $limit=10) {
    	
    	// build query:
    	// select a.* from activity as a join `user` as u on u.id=a.user_id where u.location=2 order by a.created desc;
    	$table = new Activity();
    	$select = $table->select(Zend_Db_Table::SELECT_WITH_FROM_PART)
    	->setIntegrityCheck(false)
    	->join("user", "user.id=activity.user_id")
    	->where("activity.type in (?)", array(Activity::ACTIVATE_USER, Activity::USER_ADD_BOOK));
    	$subCities = City::getSubCityIdArray($cityId);
        if (!empty($subCities)) { 
            $select = $select->where("user.location=".$cityId." OR user.location IN (".implode(",",City::getSubCityIdArray($cityId)).")");
        } else {
            $select = $select->where("user.location=?", $cityId);
        }
    	$select = $select->order("activity.created DESC")
    	->limit($limit);
    	return $table->fetchAll($select);
    }
    
    /**
     * Return 8 top users who have most available books.
     * 
     * @param $cityId cityid, like stockholm, it must be the top city
     */
    public static function getTopUsers($cityId, $num=8) {
    	// select count(*) as num, user_id from user join user_book on user.id=user_book.user_id where user_book.status='available' group by user_id order by num desc;
    	$table = new User();
    	$select = $table->select(Zend_Db_Table::SELECT_WITH_FROM_PART)
    	->setIntegrityCheck(false)
    	->from(array("u"=>"user"), array("userId"=>"u.id", "num"=>"count(*)"))
    	->join(array("ub" => "user_book"), "u.id=ub.user_id");
    	$subCities = City::getSubCityIdArray($cityId);
    	if (!empty($subCities)) { 
    		$select = $select->where("u.location=".$cityId." OR u.location IN (".implode(",",City::getSubCityIdArray($cityId)).")");
    	} else {
    		$select = $select->where("u.location=?", $cityId);
    	}
    	$select = $select->where("ub.status=?", UserBookStatus::AVAILABLE)
    	->group("u.id")
    	->order("num DESC")
    	->limit($num);
    	
    	$ret = array();
    	foreach ($table->fetchAll($select) as $result) {
    		$ret[$result->userId] = $table->findById($result->userId);
    	}
    	return $ret;
    }
    
    /**
     * Get user auth provider.
     * 
     * @param $user
     * @return return auth providers
     */
    public static function getUserAuthProvider($user) {
    	$table = new User();
    	$u = $table->findById($user->id);
    	$userCredentials = $u->findDependentRowset("UserCredentials", "User");
    	return $userCredentials;
    }
    
    /**
     * Return if user is with given auth provider.
     * 
     * @param $user
     * @param $authProvider
     * @return return auth provider's credential, if any
     */
    public static function checkUserAuthProvider($user, $authProvider) {
    	$userCredentials = self::getUserAuthProvider($user);
    	foreach ($userCredentials as $credential) {
    		if ($credential->auth_provider == $authProvider) {
    			return $credential;
    			break;
    		}
    	}
    	return null;
    }
    
    public static function getResetPasswordRequest($user) {
    	
    }
}
?>